import React, { useState, useRef, useEffect, useCallback, useMemo } from 'react';
import { VariableSizeList as List } from 'react-window';
import AutoSizer from 'react-virtualized-auto-sizer';
import MessageBubble from './MessageBubble';
import { throttle } from 'lodash';
import './VirtualMessageList.css';

interface Message {
  content: string;
  isBot: boolean;
  timestamp: string;
  isStreaming?: boolean;
  isThinking?: boolean;
  id?: string; // 用于标识消息
}

interface VirtualMessageListProps {
  messages: Message[];
  loadMoreMessages?: () => Promise<void>; // 加载更多历史消息的函数
  hasMoreMessages?: boolean; // 是否有更多历史消息
  isLoadingMore?: boolean; // 是否正在加载更多消息
  className?: string;
}

// 默认消息高度（像素）
const MIN_MESSAGE_HEIGHT = 80;
// 滚动阈值 - 当用户滚动距底部小于此值时视为"在底部"
const SCROLL_THRESHOLD = 150;
// 列表填充
const LIST_PADDING = 12;

const VirtualMessageList: React.FC<VirtualMessageListProps> = ({
  messages,
  loadMoreMessages,
  hasMoreMessages = false,
  isLoadingMore = false,
  className = '',
}) => {
  // 引用
  const listRef = useRef<List>(null);
  const outerRef = useRef<HTMLDivElement>(null);
  const messageHeightsRef = useRef<{ [key: number]: number }>({});
  
  // 状态
  const [isScrolledToBottom, setIsScrolledToBottom] = useState(true);
  const [shouldRestoreScroll, setShouldRestoreScroll] = useState(false);
  const [previousMessagesLength, setPreviousMessagesLength] = useState(0);
  const [scrollHeight, setScrollHeight] = useState(0);
  const [scrollToIndex, setScrollToIndex] = useState<number | null>(null);
  
  // 动态计算消息高度的函数
  const setMessageHeight = useCallback((index: number, height: number) => {
    if (messageHeightsRef.current[index] !== height) {
      messageHeightsRef.current[index] = height;
      // 如果列表存在，重置高度
      if (listRef.current) {
        listRef.current.resetAfterIndex(index);
      }
    }
  }, []);
  
  // 获取消息高度
  const getMessageHeight = useCallback((index: number) => {
    return messageHeightsRef.current[index] || MIN_MESSAGE_HEIGHT;
  }, []);
  
  // 监听消息变化
  useEffect(() => {
    const messagesChanged = previousMessagesLength !== messages.length;
    const isNewMessage = messages.length > previousMessagesLength;
    
    // 如果添加了新消息且用户在底部，保持滚动到底部
    if (messagesChanged && isNewMessage && isScrolledToBottom) {
      // 设置滚动到最后一条消息
      setScrollToIndex(messages.length - 1);
    }
    
    // 如果是加载了历史消息，需要保持滚动位置
    if (messagesChanged && !isNewMessage) {
      setShouldRestoreScroll(true);
      setScrollHeight(outerRef.current?.scrollHeight || 0);
    }
    
    setPreviousMessagesLength(messages.length);
  }, [messages, previousMessagesLength, isScrolledToBottom]);
  
  // 滚动还原
  useEffect(() => {
    if (shouldRestoreScroll && outerRef.current) {
      const newScrollHeight = outerRef.current.scrollHeight;
      const heightDifference = newScrollHeight - scrollHeight;
      
      if (heightDifference > 0 && outerRef.current.scrollTop >= 0) {
        outerRef.current.scrollTop += heightDifference;
      }
      
      setShouldRestoreScroll(false);
    }
  }, [shouldRestoreScroll, scrollHeight]);
  
  // 如果有指定的滚动索引，滚动到该位置
  useEffect(() => {
    if (scrollToIndex !== null && listRef.current) {
      listRef.current.scrollToItem(scrollToIndex, 'end');
      setScrollToIndex(null);
    }
  }, [scrollToIndex]);
  
  // 处理滚动事件 - 使用节流以提高性能
  const handleScroll = useMemo(
    () =>
      throttle(({ scrollOffset, scrollDirection }: { scrollOffset: number; scrollDirection: 'forward' | 'backward' }) => {
        if (outerRef.current) {
          const { scrollHeight, clientHeight } = outerRef.current;
          const scrollBottom = scrollHeight - scrollOffset - clientHeight;
          const isBottom = scrollBottom < SCROLL_THRESHOLD;
          
          setIsScrolledToBottom(isBottom);
          
          // 如果用户向上滚动且有更多历史消息，加载更多
          if (scrollOffset < 200 && scrollDirection === 'backward' && hasMoreMessages && !isLoadingMore && loadMoreMessages) {
            loadMoreMessages();
          }
        }
      }, 100),
    [hasMoreMessages, isLoadingMore, loadMoreMessages]
  );
  
  // 渲染消息行
  const renderMessage = useCallback(
    ({ index, style }: { index: number; style: React.CSSProperties }) => {
      const message = messages[index];
      
      return (
        <div style={{ ...style, paddingLeft: LIST_PADDING, paddingRight: LIST_PADDING }}>
          <MessageMeasurer
            index={index}
            message={message}
            setMessageHeight={setMessageHeight}
          />
        </div>
      );
    },
    [messages, setMessageHeight]
  );
  
  // 加载状态渲染
  const loadingIndicator = useMemo(
    () =>
      isLoadingMore && (
        <div className="history-loading-indicator">
          <div className="loading-dot"></div>
          <div className="loading-dot"></div>
          <div className="loading-dot"></div>
          <span>加载更多消息...</span>
        </div>
      ),
    [isLoadingMore]
  );
  
  // 滚动到底部按钮
  const scrollToBottomButton = useMemo(
    () =>
      !isScrolledToBottom && messages.length > 0 && (
        <button
          className="scroll-to-bottom-button"
          onClick={() => setScrollToIndex(messages.length - 1)}
        >
          <span>↓</span>
        </button>
      ),
    [isScrolledToBottom, messages.length]
  );
  
  return (
    <div className={`virtual-message-list ${className}`}>
      {loadingIndicator}
      
      <AutoSizer>
        {({ height, width }) => (
          <List
            ref={listRef}
            outerRef={outerRef}
            className="messages-list-container"
            width={width}
            height={height}
            itemCount={messages.length}
            itemSize={getMessageHeight}
            onScroll={handleScroll}
            overscanCount={5} // 预渲染数量
          >
            {renderMessage}
          </List>
        )}
      </AutoSizer>
      
      {scrollToBottomButton}
    </div>
  );
};

// 测量消息高度的组件
interface MessageMeasurerProps {
  index: number;
  message: Message;
  setMessageHeight: (index: number, height: number) => void;
}

const MessageMeasurer = React.memo(({ index, message, setMessageHeight }: MessageMeasurerProps) => {
  const measuredRef = useRef<HTMLDivElement>(null);
  
  useEffect(() => {
    if (measuredRef.current) {
      const height = Math.max(measuredRef.current.getBoundingClientRect().height, MIN_MESSAGE_HEIGHT);
      setMessageHeight(index, height);
    }
  }, [index, message.content, setMessageHeight]);
  
  return (
    <div ref={measuredRef} className="message-measurer">
      <MessageBubble
        content={message.content}
        isBot={message.isBot}
        timestamp={message.timestamp}
        isStreaming={message.isStreaming}
        isThinking={message.isThinking}
      />
    </div>
  );
});

MessageMeasurer.displayName = 'MessageMeasurer';

export default React.memo(VirtualMessageList); 